import os.path

import pandas as pd

from core.object import BarData, DataDescribe
from core.constant import *
from conf import conf
from datetime import datetime as datetime_
from tools.file_manager import data_df_interval

from typing import Callable


class DataServer:
    def __init__(self, engine):
        try:
            self.super_model = engine.super_model
        except:
            self.super_model = engine
        self.symbol_ls = []  # 字符串
        self.base_interval: Interval = None

        self.data_path: str = None  # 数据文件路径
        self.factor_ls: list = []  # 标记当前数据存在的因子值
        self.ori_data_dc: dict[str, pd.DataFrame] = None  # 由file_manager的read_csv读取的原始数据
        self.modify_time = None  # 记录csv数据文件的最后修改时间
        self.last_time = None

        self.is_live: bool = False  # 标记当前遍历的数据是否为实时数据
        self.is_end = False  # 数据流是否结束
        pass

    def load_data(self, data_path):
        self.data_path = data_path
        if conf.DataBridge.own_data_name.value not in self.data_path:
            # 加载实时或历史数据
            self.ori_data_dc: dict[str, pd.DataFrame] = self.super_model.master.file_manager.read_dc_csv(self.data_path)
            # 基础数据的interval
            csv_name = os.path.basename(self.data_path)
            data_describe_ins: DataDescribe = self.super_model.master.file_manager.describe_all_dc[csv_name]
            self.base_interval = data_describe_ins.interval_val

        else:
            if not self.super_model.master.dynamic_module_model_dc[Module.DataBridge].is_transfer:
                self.super_model.master.dynamic_module_model_dc[Module.DataBridge].is_transfer = True
            self.ori_data_dc: dict[str, pd.DataFrame] = self.super_model.master.dynamic_module_model_dc[Module.DataBridge].data_dc
            data_df = self.ori_data_dc[list(self.ori_data_dc.keys())[0]]
            self.base_interval = data_df_interval(data_df)

        # 生成因子值的列表
        columns = self.ori_data_dc[list(self.ori_data_dc.keys())[0]].columns.tolist()
        self.factor_ls = [x for x in columns if x not in conf.KChart.not_factor_ls.value]

    def update_modify_time(self, modify_time=None):
        if modify_time is None:
            if conf.DataBridge.own_data_name.value not in self.data_path:
                # 记录文件最后修改时间
                self.modify_time = datetime_.fromtimestamp(os.path.getmtime(self.data_path))
            else:
                # 记录文件最后修改时间
                self.modify_time = self.super_model.master.dynamic_module_model_dc[Module.DataBridge].modify_time
        else:
            self.modify_time = modify_time

    def traverse_data(self, on_node: Callable, on_base_bar: Callable, start_time=None, end_time=None):
        # 若am_container.members_earliest_time为空，则从头开始遍历
        symbol_ls = list(self.ori_data_dc.keys())

        if not self.is_live:
            # 找出时间最长的晚的symbol
            # last_symbol = None
            # for symbol_o in symbol_ls:
            #     if self.last_time is None:
            #         self.last_time = self.ori_data_dc[symbol_o].index[-1]
            #         last_symbol = symbol_o
            #     else:
            #         if self.ori_data_dc[symbol_o].index[-1] > self.last_time:
            #             self.last_time = self.ori_data_dc[symbol_o].index[-1]
            #             last_symbol = symbol_o
            # if self.last_time is not None:
            #     time_index = self.ori_data_dc[last_symbol].index
            # else:
            #     raise ValueError("last time为空，逻辑不符。")
            time_index = self.ori_data_dc[symbol_ls[0]].index

        # am_container.members_earliest_time不为空，则从members_earliest_time开始遍历
        else:
            # 以第一个symbol的内容为准
            sample_df = self.ori_data_dc[symbol_ls[0]]
            start_i = sample_df.index.get_loc(self.last_time)
            # 检测是否有新数据生成
            if start_i >= len(sample_df) - 1:
                # 没有新数据生成
                info = "没有新数据生成"
                self.super_model.master.file_manager.log_engine.emit(info, LogName.Running)
                return
            # 更新  self.ori_data_dc
            for k, v in self.ori_data_dc.items():
                self.ori_data_dc[k] = v.iloc[start_i + 1:, :]
            # 截取
            time_index = self.ori_data_dc[symbol_ls[0]].index
        # 遍历ori_data_dc，并将bar数据送入queue
        for time_index_o in time_index:
            # 数据过滤器
            if start_time is not None and end_time is not None:
                if time_index_o < start_time or time_index_o > end_time:
                    continue
            # 遍历当前对应的symbol
            node_dc = {}
            for symbol_o in symbol_ls:
                if time_index_o in self.ori_data_dc[symbol_o].index:
                    bar_sr = self.ori_data_dc[symbol_o].loc[time_index_o]
                    exchange = Exchange.DDQ
                    datetime = bar_sr.name
                    interval = self.base_interval
                    volume = bar_sr["volume"]
                    open_price = bar_sr["open"]
                    high_price = bar_sr["high"]
                    low_price = bar_sr["low"]
                    close_price = bar_sr["close"]
                    # 根据是否存在因子值生成bar
                    if self.factor_ls:
                        factor_sr = bar_sr[self.factor_ls]
                        base_bar: BarData = BarData(symbol_o, exchange, datetime, interval,
                                                    volume=volume, open_price=open_price, high_price=high_price,
                                                    low_price=low_price, close_price=close_price, factor_sr=factor_sr)
                    else:
                        base_bar: BarData = BarData(symbol_o, exchange, datetime, interval,
                                                    volume=volume, open_price=open_price, high_price=high_price,
                                                    low_price=low_price, close_price=close_price)
                    node_dc[symbol_o] = base_bar
                else:
                    raise ValueError(f"{symbol_o}数据在{time_index_o}存在缺失。请补充完善数据遍历逻辑，或检查数据。")
            # 行情节点传递给on_node   (1)
            on_node(node_dc)
            for symbol_o, base_bar in node_dc.items():
                # ! 放弃采用异步形式传递K线数据
                # # 待bar优先经过engine后，将数据放入queue中，任务完成
                # self.super_model.base_bar_queue.put(base_bar)
                # 基础K线节点传递给on_base_bar   (2)
                on_base_bar(base_bar)  # 将会在这里产生订单信息
            if self.is_end:
                # 接收到终止信号，遍历结束
                info = f"接收到终止信号，遍历结束。"
                self.super_model.master.file_manager.log_engine.emit(info, LogName.Operate)
                self.super_model.master.file_manager.log_engine.emit(info, LogName.Running)
                break

    def monitor(self, data_path, on_node: Callable = None, on_base_bar: Callable = None, is_traverse=False,
                start_time=None, end_time=None):
        pass

    def on_start(self):
        # if Module.KChart in self.super_model.master.dynamic_module_model_dc.keys():
        #     self.super_model.engine.start()
        if self.super_model.engine is not None:
            self.super_model.engine.start()

    def on_stop(self):
        if self.super_model.engine is not None:
            print("执行驱动引擎结束方法。")
            self.super_model.engine.stop()
        if Module.DataBridge in self.super_model.master.dynamic_module_model_dc.keys():
            self.super_model.master.dynamic_module_model_dc[Module.DataBridge].is_transfer = False
        pass


class LiveData(DataServer):
    def __init__(self, super_model):
        super().__init__(super_model)

    def monitor(self, data_path, on_node: Callable = None, on_base_bar: Callable = None, is_traverse=False,
                start_time=None, end_time=None):
        # 检测该路径的数据
        if conf.DataBridge.own_data_name.value not in data_path:
            modify_time = datetime_.fromtimestamp(os.path.getmtime(data_path))
        else:
            modify_time = self.super_model.master.dynamic_module_model_dc[Module.DataBridge].modify_time
        if self.is_end:
            self.on_stop()
            return False
        if is_traverse:
            if self.modify_time is None:
                self.load_data(data_path)
                self.update_modify_time()
                self.on_start()
                self.traverse_data(on_node, on_base_bar)
            elif modify_time > self.modify_time:
                self.load_data(data_path)
                self.update_modify_time(modify_time)
                self.is_live = True
                self.traverse_data(on_node, on_base_bar)
            else:
                return False

        else:
            if self.modify_time is None:
                self.load_data(data_path)
                self.update_modify_time()
                self.on_start()
            elif modify_time > self.modify_time:
                self.load_data(data_path)
                self.update_modify_time(modify_time)
                self.is_live = True
            else:
                return False

        return True


class HistoryData(DataServer):
    def __init__(self, engine):
        super().__init__(engine)

    def monitor(self, data_path, on_node: Callable = None, on_base_bar: Callable = None, is_traverse=False,
                start_time=None, end_time=None):
        # 实际仅读取一次
        self.load_data(data_path)
        self.on_start()

        if is_traverse:
            self.traverse_data(on_node, on_base_bar, start_time, end_time)
            self.on_stop()
            return True
        else:
            return True

    def only_traverse(self, data_path, on_node: Callable = None, on_base_bar: Callable = None, start_time=None,
                      end_time=None):
        self.load_data(data_path)
        self.traverse_data(on_node, on_base_bar, start_time, end_time)
        return True

